// 函数节流(Throttle)实现
/**
 * 函数节流：在指定时间内，无论调用多少次，函数最多执行一次
 * 应用场景：滚动事件、窗口调整、鼠标移动等高频触发的事件
 * 
 * @param {Function} fn - 需要节流的函数
 * @param {number} delay - 节流的时间间隔（毫秒）
 * @returns {Function} 节流后的函数
 */
function throttle(fn, delay) {
  // 记录上一次执行的时间戳
  let lastTime = 0;
  
  // 返回节流后的函数
  return function(...args) {
    // 获取当前时间戳
    const now = Date.now();
    
    // 如果当前时间与上一次执行时间的差大于等于delay，则执行函数
    if (now - lastTime >= delay) {
      // 执行函数并绑定this
      fn.apply(this, args);
      // 更新上一次执行的时间戳
      lastTime = now;
    }
  };
}

// 函数防抖(Debounce)实现
/**
 * 函数防抖：在连续多次调用后，只执行最后一次调用或第一次调用
 * 应用场景：搜索输入、表单验证、窗口调整完成后执行操作等
 * 
 * @param {Function} fn - 需要防抖的函数
 * @param {number} delay - 防抖的时间间隔（毫秒）
 * @param {boolean} immediate - 是否立即执行第一次调用，默认为false
 * @returns {Function} 防抖后的函数
 */
function debounce(fn, delay, immediate = false) {
  // 用于存储定时器ID
  let timeout = null;
  
  // 返回防抖后的函数
  return function(...args) {
    // 保存this上下文
    const context = this;
    
    // 清除之前的定时器
    if (timeout) clearTimeout(timeout);
    
    // 立即执行的情况
    if (immediate) {
      // 如果是第一次调用或距离上次调用已超过delay，则执行
      const callNow = !timeout;
      
      // 设置新的定时器
      timeout = setTimeout(() => {
        timeout = null;
      }, delay);
      
      // 立即执行函数
      if (callNow) fn.apply(context, args);
    } else {
      // 非立即执行的情况：设置新的定时器，延迟执行
      timeout = setTimeout(() => {
        fn.apply(context, args);
      }, delay);
    }
  };
}

// 加强版节流：结合节流和防抖的特性
/**
 * 加强版节流：先执行一次，然后在指定时间内不再执行，最后一次调用也会执行
 * 应用场景：既需要立即响应，又需要限制执行频率的场景
 * 
 * @param {Function} fn - 需要节流的函数
 * @param {number} delay - 节流的时间间隔（毫秒）
 * @returns {Function} 加强版节流后的函数
 */
function throttleEnhanced(fn, delay) {
  let lastTime = 0;
  let timeout = null;
  
  return function(...args) {
    const now = Date.now();
    const remaining = delay - (now - lastTime);
    const context = this;
    
    // 清除之前的定时器
    if (timeout) clearTimeout(timeout);
    
    // 如果距离上次执行的时间已经超过delay，立即执行
    if (remaining <= 0) {
      fn.apply(context, args);
      lastTime = now;
    } else {
      // 否则设置定时器，确保最后一次调用也能执行
      timeout = setTimeout(() => {
        fn.apply(context, args);
        lastTime = Date.now();
      }, remaining);
    }
  };
}

// 测试函数
function testFunction(type) {
  console.log(`${type} 函数执行了，时间: ${new Date().toLocaleTimeString()}`);
}

// 使用示例
console.log('=== 函数节流、防抖测试 ===');

// 测试节流函数
const throttledFn = throttle(() => testFunction('节流'), 1000);
console.log('--- 测试节流函数 (每1000ms最多执行一次) ---');

// 模拟连续调用10次
for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    throttledFn();
  }, i * 300); // 每300ms调用一次
}

// 测试防抖函数 - 非立即执行
const debouncedFn = debounce(() => testFunction('防抖(非立即)'), 1000);
console.log('--- 测试防抖函数 (非立即执行，连续调用后只执行最后一次) ---');

// 模拟连续调用5次
setTimeout(() => {
  for (let i = 0; i < 5; i++) {
    setTimeout(() => {
      debouncedFn();
    }, i * 200); // 每200ms调用一次
  }
}, 3000);

// 测试防抖函数 - 立即执行
const debouncedImmediateFn = debounce(() => testFunction('防抖(立即)'), 1000, true);
console.log('--- 测试防抖函数 (立即执行，第一次调用立即执行) ---');

// 模拟连续调用5次
setTimeout(() => {
  for (let i = 0; i < 5; i++) {
    setTimeout(() => {
      debouncedImmediateFn();
    }, i * 200); // 每200ms调用一次
  }
}, 6000);

// 测试加强版节流
const enhancedThrottledFn = throttleEnhanced(() => testFunction('加强版节流'), 1000);
console.log('--- 测试加强版节流 (结合节流和防抖的特性) ---');

// 模拟连续调用10次
setTimeout(() => {
  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      enhancedThrottledFn();
    }, i * 300); // 每300ms调用一次
  }
}, 9000);

/**
 * 节流与防抖的区别与应用场景：
 * 
 * 1. 函数节流 (Throttle):
 *    - 原理：在指定的时间间隔内，函数最多执行一次
 *    - 特点：保证函数在一定时间内至少执行一次
 *    - 应用场景：
 *      - 滚动事件处理（如无限滚动加载）
 *      - 窗口调整大小事件
 *      - 鼠标移动事件（如拖拽）
 *      - 视频播放进度条
 * 
 * 2. 函数防抖 (Debounce):
 *    - 原理：在连续多次调用后，只执行最后一次（或第一次）
 *    - 特点：只有当事件停止触发后才执行函数
 *    - 应用场景：
 *      - 搜索框输入联想
 *      - 表单验证
 *      - 按钮点击防重复提交
 *      - 窗口调整完成后执行操作
 * 
 * 3. 加强版节流:
 *    - 原理：结合了节流和防抖的优点
 *    - 特点：既保证了第一次调用立即执行，又保证了最后一次调用也能执行
 *    - 应用场景：既需要立即响应，又需要限制执行频率的场景
 */